#include "object.hpp"
#include "protocol.hpp"

#include "commons.hpp"

#include "medved/manager.hpp"

using namespace Medved;

namespace Server
{
	#define IMPLEMENT_CLONE(T)\
	T *T::clone() const\
	{\
		return new T(*this);\
	}

	Object::~Object()
	{
	}

	Obstacle *Obstacle::damage(int power)
	{
		life_ -= power;
		if (life_ <= 0) {
			delete this;
			return 0;
		}
		else
			return this;
	}
	
	unsigned char Forest::objectId() const
	{
		return Proto::FIELD_FOREST;
	}

	IMPLEMENT_CLONE(Forest)
	
	Obstacle *Bridge::damage(int power)
	{
		if (Obstacle::damage(power) != 0)
			return this;
		else
			return new River();
	}
	
	unsigned char Bridge::objectId() const
	{
		return Proto::FIELD_BRIDGE;
	}

	IMPLEMENT_CLONE(Bridge)

	River *River::enter(Player &player)
	{
		player.kill();
		return this;
	}
	
	unsigned char River::objectId() const
	{
		return Proto::FIELD_RIVER;
	}

	IMPLEMENT_CLONE(River)

	Swamp* Swamp::enter(Player &player)
	{
		player.isInSwamp = true;
		if (player.velocityModulo() > SWAMP_MAX_VELOCITY)
			player.brake();
		return this;
	}

	Swamp* Swamp::leave(Player &player)
	{
		player.isInSwamp = false;
		return this;
	}
	
	unsigned char Swamp::objectId() const
	{
		return Proto::FIELD_SWAMP;
	}

	IMPLEMENT_CLONE(Swamp)
	
	void Bonus::scheduleCancel(int time, const Player &player, short Player::*property, short value)
	{
		TheScheduler::instance().schedule(time, bind(
					Bonus::cancel, player.getId(), property, value));
	}
	
	void Bonus::cancel(int playerId, short Player::*property, short value)
	{
		Player *player = static_cast<Player *>(TheManager::instance().get(playerId));
		if (player)
			player->*property -= value;
	}
	
	ChargeStation *ChargeStation::timeStep(Player &player)
	{
		player.adjustEnergy(CHARGE_STATION_GAIN);
		return this;
	}
	
	unsigned char ChargeStation::objectId() const
	{
		return Proto::FIELD_CHARGE_STATION;
	}

	IMPLEMENT_CLONE(ChargeStation)

	void ObjectHolder::setObject(Object *obj)
	{
		delete obj_;
		obj_ = obj;
		++objectNumber_;
	}

	void ObjectHolder::enter(Player &player)
	{
		if (obj_)
			obj_ = obj_->enter(player);
	}

	void ObjectHolder::leave(Player &player)
	{
		if (obj_)
			obj_ = obj_->leave(player);
	}

	void ObjectHolder::timeStep(Player &player)
	{
		if (obj_)
			obj_ = obj_->timeStep(player);
	}

	void ObjectHolder::damage(int value)
	{
		if (obj_)
			obj_ = obj_->damage(value);
	}
	
	unsigned char ObjectHolder::objectId() const
	{
		if (obj_)
			return obj_->objectId();
		else
			return Proto::FIELD_EMPTY;
	}

}
